﻿using System.Collections;

namespace Chap12_Generic
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello, World!");

            Farm<Animal> farm = new Farm<Animal>();
            farm.Animals.Add(new Cow("Rual"));
            farm.Animals.Add(new Chicken("Donna"));
            farm.Animals.Add(new Chicken("Mary"));
            farm.Animals.Add(new SuperCow("Ben"));
            farm.MakeMoises();

            Farm<Cow> cows = farm.GetCows();
            cows.FeedAnimals();
            foreach (Cow item in cows)
            {
                if (item is SuperCow)
                {
                    (item as SuperCow).Fly();
                }
            }

            Console.ReadKey();
        }
    }

    public abstract class Animal
    {
        protected string name;
        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        public Animal() => name = "The animal with no name";

        public Animal(string name) => this.name = name;

        public void Feed() => Console.WriteLine($"{name} has been fed.");

        public abstract void MakeSound();
    }

    public class Cow : Animal
    {
        public void Milk() => Console.WriteLine($"{name} has been milked.");

        public override void MakeSound()
        {
           Console.WriteLine($"{name} says 'moo!'");
        }

        public Cow(string newName) : base(newName) { }
    }

    public class Chicken : Animal
    {
        public void LayEgg() => Console.WriteLine($"{name} has laid an egg.");

        public Chicken(string newName) : base(newName) { }
        public override void MakeSound()
        {
            Console.WriteLine($"{name} says 'cluck!'");
        }
    }

    public class SuperCow : Cow
    {
        public void Fly() => Console.WriteLine($"{name} is Flying.");

        public override void MakeSound()
        {
            Console.WriteLine($"{name} says 'here I come to save the day!'");
        }

        public SuperCow(string newName) : base(newName) { }
    }

    public class Farm<T> : IEnumerable<T> where T : Animal
    {
        private List<T> animals = new List<T>();

        public List<T> Animals
        {
            get { return animals; }
            set { animals = value; }
        }

        public IEnumerator<T> GetEnumerator()
        {
            return animals.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return animals.GetEnumerator();
        }

        public void MakeMoises()
        {
            foreach (T animal in animals)
            {
                animal.MakeSound();
            }
        }

        public void FeedAnimals()
        {
            foreach (T animal in animals)
            {
                animal.Feed();
            }
        }

        public Farm<Cow> GetCows()
        {
            Farm<Cow> cows = new Farm<Cow>();
            foreach (T animal in animals)
            {
                if (animal is Cow)
                {
                    cows.Animals.Add(animal as Cow);
                }
            }
            return cows;
        }
    }
}
